package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.common.converter;

import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.databind.JsonNode;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.context.FlowElementProcessContext;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.threadlocal.DeployIdContainer;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.SubProcessActivityProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import org.flowable.bpmn.model.BaseElement;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.SubProcess;
import org.flowable.editor.language.json.converter.ActivityProcessor;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.SubProcessJsonConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lich
 * @date 2021-10-31 20:17
 */
public class CustomSubProcessJsonConverter extends SubProcessJsonConverter {

    private  static Logger  logger  = LoggerFactory.getLogger(CustomSubProcessJsonConverter.class);

    private FlowElement currentFlowElement;

    public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {

        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_SUB_PROCESS, CustomSubProcessJsonConverter.class);
        convertersToBpmnMap.put(STENCIL_COLLAPSED_SUB_PROCESS, CustomSubProcessJsonConverter.class);
    }

    public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(SubProcess.class, CustomSubProcessJsonConverter.class);
    }

    @Override
    public void convertToBpmnModel(JsonNode elementNode, JsonNode modelNode, ActivityProcessor processor, BaseElement parentElement, Map<String, JsonNode> shapeMap, BpmnModel bpmnModel) {
        super.convertToBpmnModel(elementNode, modelNode, processor, parentElement, shapeMap, bpmnModel);
        try {
            if (Objects.nonNull(this.currentFlowElement)) {
                //todo 该阶段可以处理节点中的扩展属性，属性值可以从elementNode中获取
                if (currentFlowElement instanceof SubProcess) {
                    SubProcess subProcess = (SubProcess) currentFlowElement;
                    executeSubProcessActivityProcessor(subProcess, elementNode, modelNode);
                }
            }
        } finally {
            this.currentFlowElement = null;
        }
    }

    private void executeSubProcessActivityProcessor(SubProcess subProcess, JsonNode elementNode, JsonNode modelNode) {
        Map<String, SubProcessActivityProcessor> subProcessActivityProcessorMap = SpringUtils.getApplicationContext().getBeansOfType(SubProcessActivityProcessor.class);
        for (SubProcessActivityProcessor subProcessActivityProcessor : subProcessActivityProcessorMap.values()) {
            if (subProcessActivityProcessor.support(subProcess)) {
                try{
                    subProcessActivityProcessor.process(FlowElementProcessContext.builder().deployId(DeployIdContainer.getDeployId())
                            .elementNode(elementNode)
                            .modelNode(modelNode)
                            .nodeCode(subProcess.getId())
                            .activity(subProcess)
                            .build()
                    );
                }catch (Exception e){
                    logger.error("executeSubProcessActivityProcessor Error,Reason:"+e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap) {
        this.currentFlowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap);
        return currentFlowElement;
    }

}
